package se.webbzon.oschi01.item;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.SortedSet;
import java.util.TreeSet;

import se.webbzon.oschi01.metric.Metric;
import se.webbzon.oschi01.metric.XWangMetric;

public class ItemSet implements SortedSet<ItemEntry> {
	
	private final TreeSet<ItemEntry> tree;
	
	public ItemSet() {
		this(null);
	}
	
	public ItemSet(Collection<ItemEntry> entries) {
		tree = new TreeSet<ItemEntry>(new ComparatorImpl());
		if (entries != null)	
			tree.addAll(entries);
	}
	
	public Collection<ItemEntry> match(String regex) {
		return match(regex,-1);
	}
	
	public Collection<ItemEntry> match(String regex, int limit) {
		Collection<ItemEntry> matches = new ArrayList<ItemEntry>();
		if (limit == 0)
			return matches;
		else {
			for (ItemEntry entry : tree) {
				if (entry.toString().matches(regex)) {
					matches.add(entry);
					if (limit == 1)
						break;
					else
						limit--;
				}
			}
			return matches;
		}
	}
	
	public SortedSet<ItemEntry> similar(ItemEntry e) {
		ItemEntryMetric metric = new ItemEntryMetric(new XWangMetric());
		return similar(e,metric,-1,1);
	}
	
	public SortedSet<ItemEntry> similar(ItemEntry e, Metric<ItemEntry> metric, int limit, double tolerance) {
		TreeSet<ItemEntry> entries = new TreeSet<ItemEntry>();
		if (limit == 0)
			return entries;
		else {
			for (ItemEntry entry : tree) {
				double score = metric.distance(e, entry);
				if (score <= tolerance) {
					entries.add(new ComparableItemEntry(entry,score));
					if (limit == 1)
						break;
					else
						limit--;
				}
			}
			return entries;
		}
	}
	
	public Map<ItemEntry,ItemEntry> mapTo(ItemSet set) {
		Map<ItemEntry,ItemEntry> map = new HashMap<ItemEntry,ItemEntry>();
		TreeSet<ItemEntry> tmp = new TreeSet<ItemEntry>(set);
		for (ItemEntry entry : tree) {
			for (ItemEntry o : tmp) {
				if (ItemEntryComparator.isEqual(entry,o)) {
					tmp.remove(o);
					map.put(entry, o);
					break;
				}
			}
		}
		return map;
	}
	
	@Override public boolean add(ItemEntry e) {
		return tree.add(e);
	}

	@Override public boolean addAll(Collection<? extends ItemEntry> c) {
		return tree.addAll(c);
	}

	@Override public void clear() {
		tree.clear();
	}

	@Override public boolean contains(Object o) {
		return tree.contains(o);
	}

	@Override public boolean containsAll(Collection<?> c) {
		return tree.containsAll(c);
	}

	@Override public boolean isEmpty() {
		return tree.isEmpty();
	}

	@Override public boolean remove(Object o) {
		return tree.remove(o);
	}

	@Override public boolean removeAll(Collection<?> c) {
		return tree.removeAll(c);
	}

	@Override public boolean retainAll(Collection<?> c) {
		return tree.retainAll(c);
	}

	@Override public int size() {
		return tree.size();
	}

	@Override public Object[] toArray() {
		return tree.toArray();
	}

	@Override public <T> T[] toArray(T[] a) {
		return tree.toArray(a);
	}

	@Override public Comparator<? super ItemEntry> comparator() {
		return tree.comparator();
	}

	@Override public ItemEntry first() {
		return tree.first();
	}

	@Override public SortedSet<ItemEntry> headSet(ItemEntry toElement) {
		return tree.headSet(toElement);
	}

	@Override public ItemEntry last() {
		return tree.last();
	}

	@Override public SortedSet<ItemEntry> subSet(ItemEntry fromElement, ItemEntry toElement) {
		return tree.subSet(fromElement, toElement);
	}

	@Override public SortedSet<ItemEntry> tailSet(ItemEntry fromElement) {
		return tree.tailSet(fromElement);
	}

	@Override public Iterator<ItemEntry> iterator() {
		return tree.iterator();
	}
	
	private final class ComparatorImpl implements Comparator<ItemEntry> {

		@Override public int compare(ItemEntry arg0, ItemEntry arg1) {
			return arg0.getId() - arg1.getId();
		}
		
	}
	
	public final class ComparableItemEntry extends ItemEntry implements Comparable<ComparableItemEntry> {

		public final ItemEntry e;
		
		public final double score;
		
		public ComparableItemEntry(ItemEntry e, double score) {
			this.e = e;
			this.score = score;
		}
		
		@Override public int compareTo(ComparableItemEntry arg0) {
			if (score == arg0.score)
				return getId() - arg0.getId();
			else if (score < arg0.score)
				return -1;
			else
				return 1;
		}

		@Override public int getId() {
			return e.getId();
		}

		@Override public ItemType getType() {
			return e.getType();
		}
		
		@Override public String getMod() {
			return e.getMod();
		}

		@Override public String getClassName() {
			return e.getClassName();
		}

		@Override public String getUnlocalisedName() {
			return e.getUnlocalisedName();
		}
		
	}

}
